package cn.yilongquan.controller;

import cn.hutool.extra.servlet.ServletUtil;
import cn.yilongquan.mapper.LogMapper;
import cn.yilongquan.user.domain.LogEntity;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.UUID;

@Slf4j
@Aspect
@Component
public class LogAspect {

    @Autowired
    private LogMapper logMapper;

    // 定义切点，这里拦截博客文章模块（假设文章相关 Service 类在 com.example.service.article 包下，且方法名包含 save、delete、update ）
    // 可根据实际包名、类名、方法名调整切点表达式
    @Around("execution(* cn.yilongquan.service..*(..)) && (execution(* add*(..)) || execution(* delete*(..)) || execution(* update*(..)))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 1. 获取请求相关信息（用于获取 ip 等）
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        // 2. 构建日志实体对象
        LogEntity logEntity = new LogEntity();
        logEntity.setCreateTime(new Date());
        logEntity.setIp(ServletUtil.getClientIP(request)); // 使用 Hutool 工具类获取客户端 IP，也可自己实现获取逻辑
        
        // 3. 获取用户信息（假设已登录，从 session 或 token 中获取，这里简单模拟，实际根据项目鉴权方式调整）
        // 示例：从 session 获取，若用 token 则解析 token 获取
        // Object user = request.getSession().getAttribute("user"); 
        // if (user != null) {
        //     logEntity.setUserId(((User) user).getId());
        //     logEntity.setUserName(((User) user).getUserName());
        // }
        // 这里先模拟固定值，实际项目替换为真实获取逻辑
        logEntity.setUserId(1L); // 替换为真实用户 ID 获取逻辑
        logEntity.setUserName("testUser"); // 替换为真实用户名获取逻辑

        // 4. 获取目标方法信息
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        logEntity.setClassName(joinPoint.getTarget().getClass().getName());
        logEntity.setMethodName(method.getName());

        // 5. 获取方法参数
        Object[] args = joinPoint.getArgs();
        // 这里简单将参数转为字符串，可根据需要用 JSON 工具类（如 Fastjson、Jackson ）序列化为 JSON 字符串
        StringBuilder params = new StringBuilder();
        for (Object arg : args) {
            params.append(arg).append(", ");
        }
        if (params.length() > 0) {
            params.deleteCharAt(params.length() - 2); // 去掉最后一个 ", " 
        }
        logEntity.setMethodParams(params.toString());

        // 6. 执行目标方法，记录开始时间
        long startTime = System.currentTimeMillis();
        Object result = joinPoint.proceed(); // 执行原方法
        long costTime = System.currentTimeMillis() - startTime;
        logEntity.setCostTime(costTime);

        // 7. 获取方法返回值
        logEntity.setReturnValue(result != null ? result.toString() : "");

        // 7. 保存日志（核心：添加异常捕获）
        try {
            // 打印准备插入的日志信息（方便调试）
            log.info("准备插入日志：{}", logEntity);
            // 调用mapper保存日志
            logMapper.saveLog(logEntity);
            log.info("日志插入成功！");
        } catch (Exception e) {
            // 关键：打印具体错误信息，包括SQL异常详情
            log.error("日志插入失败！原因：", e);
        }

        return result;
    }
}